// Copyright 2022 a.o.smith ALL Rights Reserved
package com.liuxinlong.utils;

import com.liuxinlong.common.AosException;
import com.liuxinlong.enums.ReturnCodes;
import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;

/**
 * 时间处理工具类
 *
 * @author liuxinlong@hotwater.com.cn
 * @version 1.0.0
 * @since 2022-03-11
 */
@Slf4j
public class TimeUtils {
    private static final long ONE_MINUTE = 60;
    private static final long ONE_HOUR = 3600;
    private static final long ONE_DAY = 86400;
    private static final long ONE_MONTH = 2592000;
    private static final long ONE_YEAR = 31104000;

    public static Calendar calendar = Calendar.getInstance();

    /**
     * @return yyyy-mm-dd
     * 2012-12-25
     */
    public static String getDate() {
        return getYear() + "-" + getMonth() + "-" + getDay();
    }

    /**
     * @param format
     * @return yyyy年MM月dd HH:mm
     * MM-dd HH:mm 2012-12-25
     */
    public static String getDate(String format) {
        SimpleDateFormat simple = new SimpleDateFormat(format);
        Date date = new Date();
        System.out.println("date: " + date);
        log.info("date1: " + date);
        return simple.format(date);
    }

    /**
     * 距离今天多久
     *
     * @param date
     * @return
     */
    public static String fromToday(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        long time = date.getTime() / 1000;
        long now = new Date().getTime() / 1000;
        long ago = now - time;
        if (ago <= ONE_HOUR)
            return ago / ONE_MINUTE + "分钟前";
        else if (ago <= ONE_DAY)
            return ago / ONE_HOUR + "小时" + (ago % ONE_HOUR / ONE_MINUTE)
                    + "分钟前";
        else if (ago <= ONE_DAY * 2)
            return "昨天" + calendar.get(Calendar.HOUR_OF_DAY) + "点"
                    + calendar.get(Calendar.MINUTE) + "分";
        else if (ago <= ONE_DAY * 3)
            return "前天" + calendar.get(Calendar.HOUR_OF_DAY) + "点"
                    + calendar.get(Calendar.MINUTE) + "分";
        else if (ago <= ONE_MONTH) {
            long day = ago / ONE_DAY;
            return day + "天前" + calendar.get(Calendar.HOUR_OF_DAY) + "点"
                    + calendar.get(Calendar.MINUTE) + "分";
        } else if (ago <= ONE_YEAR) {
            long month = ago / ONE_MONTH;
            long day = ago % ONE_MONTH / ONE_DAY;
            return month + "个月" + day + "天前"
                    + calendar.get(Calendar.HOUR_OF_DAY) + "点"
                    + calendar.get(Calendar.MINUTE) + "分";
        } else {
            long year = ago / ONE_YEAR;
            int month = calendar.get(Calendar.MONTH) + 1;// JANUARY which is 0 so month+1
            return year + "年前" + month + "月" + calendar.get(Calendar.DATE)
                    + "日";
        }

    }

    /**
     * 距离截止日期还有多长时间
     *
     * @param date
     * @return
     */
    public static String fromDeadline(Date date) {
        long deadline = date.getTime() / 1000;
        long now = (new Date().getTime()) / 1000;
        long remain = deadline - now;
        if (remain <= ONE_HOUR)
            return "只剩下" + remain / ONE_MINUTE + "分钟";
        else if (remain <= ONE_DAY)
            return "只剩下" + remain / ONE_HOUR + "小时"
                    + (remain % ONE_HOUR / ONE_MINUTE) + "分钟";
        else {
            long day = remain / ONE_DAY;
            long hour = remain % ONE_DAY / ONE_HOUR;
            long minute = remain % ONE_DAY % ONE_HOUR / ONE_MINUTE;
            return "只剩下" + day + "天" + hour + "小时" + minute + "分钟";
        }

    }

    /**
     * 距离截止日期还有多少天
     *
     * @param date
     * @return
     */
    public static String fromDeadlineDays(Date date) {
        long deadline = date.getTime() / 1000;
        long now = (new Date().getTime()) / 1000;
        long remain = deadline - now;
        if (remain < 0) {
            return "已超时";
        } else if (remain <= ONE_HOUR)
            return remain / ONE_MINUTE + "分钟";
        else if (remain <= ONE_DAY)
            return remain / ONE_HOUR + "小时"
                    + (remain % ONE_HOUR / ONE_MINUTE) + "分钟";
        else {
            long day = remain / ONE_DAY;
            long hour = remain % ONE_DAY / ONE_HOUR;
            long minute = remain % ONE_DAY % ONE_HOUR / ONE_MINUTE;
            return day + "天" + hour + "小时" + minute + "分钟";
        }

    }

    /**
     * 距离今天的绝对时间
     *
     * @param date
     * @return
     */
    public static String toToday(Date date) {
        long time = date.getTime() / 1000;
        long now = (new Date().getTime()) / 1000;
        long ago = now - time;
        if (ago <= ONE_HOUR)
            return ago / ONE_MINUTE + "分钟";
        else if (ago <= ONE_DAY)
            return ago / ONE_HOUR + "小时" + (ago % ONE_HOUR / ONE_MINUTE) + "分钟";
        else if (ago <= ONE_DAY * 2)
            return "昨天" + (ago - ONE_DAY) / ONE_HOUR + "点" + (ago - ONE_DAY)
                    % ONE_HOUR / ONE_MINUTE + "分";
        else if (ago <= ONE_DAY * 3) {
            long hour = ago - ONE_DAY * 2;
            return "前天" + hour / ONE_HOUR + "点" + hour % ONE_HOUR / ONE_MINUTE
                    + "分";
        } else if (ago <= ONE_MONTH) {
            long day = ago / ONE_DAY;
            long hour = ago % ONE_DAY / ONE_HOUR;
            long minute = ago % ONE_DAY % ONE_HOUR / ONE_MINUTE;
            return day + "天前" + hour + "点" + minute + "分";
        } else if (ago <= ONE_YEAR) {
            long month = ago / ONE_MONTH;
            long day = ago % ONE_MONTH / ONE_DAY;
            long hour = ago % ONE_MONTH % ONE_DAY / ONE_HOUR;
            long minute = ago % ONE_MONTH % ONE_DAY % ONE_HOUR / ONE_MINUTE;
            return month + "个月" + day + "天" + hour + "点" + minute + "分前";
        } else {
            long year = ago / ONE_YEAR;
            long month = ago % ONE_YEAR / ONE_MONTH;
            long day = ago % ONE_YEAR % ONE_MONTH / ONE_DAY;
            return year + "年前" + month + "月" + day + "天";
        }

    }

    public static String getYear() {
        return calendar.get(Calendar.YEAR) + "";
    }

    public static String getMonth() {
        int month = calendar.get(Calendar.MONTH) + 1;
        return month + "";
    }

    public static String getDay() {
        return calendar.get(Calendar.DATE) + "";
    }

    public static String get24Hour() {
        return calendar.get(Calendar.HOUR_OF_DAY) + "";
    }

    public static String getMinute() {
        return calendar.get(Calendar.MINUTE) + "";
    }

    public static String getSecond() {
        return calendar.get(Calendar.SECOND) + "";
    }

    public static String formatTime(String targetTime, String inputFormat, String outputFormat) {
        Date date;
        SimpleDateFormat sf1 = new SimpleDateFormat(inputFormat);
        SimpleDateFormat sf2 = new SimpleDateFormat(outputFormat);
//        simple.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));//设置时区为东八区
        try {
            date = sf1.parse(targetTime);
        } catch (Exception e) {
            throw new AosException(ReturnCodes.HTTP_SYSTEM_ERROR, "时间转换异常");
        }
        return sf2.format(date);
    }

    public static String formatTime(Date targetTime, String outputFormat) {
        SimpleDateFormat sf = new SimpleDateFormat(outputFormat);
        return sf.format(targetTime);
    }

    public static Date formatTime(String targetTime, String inputFormat) {
        SimpleDateFormat sf = new SimpleDateFormat(inputFormat);
        Date date;
        try {
            date = sf.parse(targetTime);

        } catch (Exception e) {
            throw new AosException(ReturnCodes.HTTP_SYSTEM_ERROR, "时间转换异常");
        }
        return date;
    }

    /**
     * 比较两个时间相差天数
     *
     * @param time1 起始时间
     * @param time2 截止时间
     * @return 时间相差天数
     */
    public static float calculateTimeGapDay(String time1, String time2, String timeFormat) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(timeFormat);

        float day = 0;
        Date date1 = null;
        Date date2 = null;

        try {
            date1 = simpleDateFormat.parse(time1);
            date2 = simpleDateFormat.parse(time2);
            long millisecond = date2.getTime() - date1.getTime();
            day = millisecond / (24 * 60 * 60 * 1000);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return day;
    }

    /**
     * 比较两个时间相差秒数
     *
     * @param time1 起始时间
     * @param time2 截止时间
     * @return 时间相差秒数
     */
    public static float calculateTimeGapSecond(String time1, String time2, String timeFormat) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(timeFormat);

        float second = 0;
        Date date1 = null;
        Date date2 = null;

        try {
            date1 = simpleDateFormat.parse(time1);
            date2 = simpleDateFormat.parse(time2);
            long millisecond = date2.getTime() - date1.getTime();
            second = millisecond / 1000;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return second;
    }

    /**
     * 获取当前时间前一小时的时间
     *
     * @param time       原时间
     * @param timeFormat 时间格式
     * @return 当前时间前一小时的时间
     */
    public static String beforeOneHourToNowDate(String time, String timeFormat) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(timeFormat);
        Date dateOriginal;
        String transTime = null;
        try {
            dateOriginal = simpleDateFormat.parse(time);
            Calendar calendar = Calendar.getInstance();
            /* HOUR_OF_DAY 指示一天中的小时 */
            calendar.setTime(dateOriginal);
            calendar.add(Calendar.HOUR_OF_DAY, -1);
            transTime = simpleDateFormat.format(calendar.getTime());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return transTime;
    }

    /**
     * 获取本月第一天
     *
     * @return 本月第一天
     */
    public static String getMonthFirstDay() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.add(Calendar.MONTH, 0);
        return new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime());
    }

    /**
     * 获取本月最后一天
     *
     * @return 本月最后一天
     */
    public static String getMonthLastDay() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime());
    }

    /**
     * 获取本周的第一天
     *
     * @return String
     **/
    public static String getWeekStart() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.WEEK_OF_MONTH, 0);
        cal.set(Calendar.DAY_OF_WEEK, 2);
        Date time = cal.getTime();
        return new SimpleDateFormat("yyyy-MM-dd").format(time) + " 00:00:00";
    }

    /**
     * 获取本周的最后一天
     *
     * @return String
     **/
    public static String getWeekEnd() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_WEEK, cal.getActualMaximum(Calendar.DAY_OF_WEEK));
        cal.add(Calendar.DAY_OF_WEEK, 1);
        Date time = cal.getTime();
        return new SimpleDateFormat("yyyy-MM-dd").format(time) + " 23:59:59";
    }

    /**
     * 获取本季的第一天
     *
     * @return 本季的第一天
     */
    public static String getCurrentQuarterStartTime() {
        Calendar c = Calendar.getInstance();
        int currentMonth = c.get(2) + 1;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String firstDayOfCurrentQuarter = null;
        try {
            if (currentMonth <= 3) {
                c.set(2, 0);
            } else if (currentMonth <= 6) {
                c.set(2, 3);
            } else if (currentMonth <= 9) {
                c.set(2, 4);
            } else if (currentMonth <= 12) {
                c.set(2, 9);
            }
            c.set(5, 1);
            firstDayOfCurrentQuarter = sdf.format(c.getTime());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return firstDayOfCurrentQuarter;
    }

    /**
     * 获取本季的最后一天
     *
     * @return 本季的最后一天
     **/
    public static String getCurrentQuarterEndTime() {
        Calendar c = Calendar.getInstance();
        int currentMonth = c.get(2) + 1;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String lastDayOfCurrentQuarter = null;
        try {
            if (currentMonth <= 3) {
                c.set(2, 2);
                c.set(5, 31);
            } else if (currentMonth <= 6) {
                c.set(2, 5);
                c.set(5, 30);
            } else if (currentMonth <= 9) {
                c.set(2, 8);
                c.set(5, 30);
            } else if (currentMonth <= 12) {
                c.set(2, 11);
                c.set(5, 31);
            }
            lastDayOfCurrentQuarter = sdf.format(c.getTime());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return lastDayOfCurrentQuarter;
    }

    /**
     * 获取本年的第一天
     *
     * @return 本年的第一天
     */
    public static String getCurrentYearStart() {
        return (new SimpleDateFormat("yyyy")).format(new Date()) + "-01-01";
    }

    /**
     * 获取本年的最后一天
     *
     * @return 本年的最后一天
     **/
    public static String getCurrentYearEnd() {
        return (new SimpleDateFormat("yyyy")).format(new Date()) + "-12-31";
    }

    /**
     * 获取指定年份的第一天
     *
     * @return 指定年份的第一天
     */
    public static String getYearStart(Date time) {
        return (new SimpleDateFormat("yyyy")).format(time) + "-01-01";
    }

    /**
     * 获取指定年份的最后一天
     *
     * @return 指定年份的最后一天
     **/
    public static String getYearEnd(Date time) {
        return (new SimpleDateFormat("yyyy")).format(time) + "-12-31";
    }

    /**
     * 比较时间
     * date1 > date2 1
     * date1 < date2 -1
     *
     * @return String
     **/
    public static int compareDate(String time1, String time2, String timeFormat) {
        SimpleDateFormat sdf = new SimpleDateFormat(timeFormat);
        try {
            Date date1 = sdf.parse(time1);
            Date date2 = sdf.parse(time2);
            return date1.compareTo(date2);
        } catch (Exception e) {
            throw new AosException(ReturnCodes.HTTP_SYSTEM_ERROR);
        }

    }

    /**
     * 获取距离当前时间N天前时间
     *
     * @param time       当前时间
     * @param days       N天
     * @param timeFormat 格式
     * @return 距离当前时间N天前时间
     */
    public static String getDaysAgo(String time, int days, String timeFormat) {
        LocalDate today = LocalDate.parse(time);
        LocalDate targetDay = today.minusDays(days);
        Date date = Date.from(targetDay.atStartOfDay(ZoneId.systemDefault()).toInstant());
        SimpleDateFormat sdf = new SimpleDateFormat(timeFormat);
        return sdf.format(date);
    }

    /**
     * 获取指定日期的前N天
     *
     * @param dateTime   指定日期
     * @param days       前N天
     * @param timeFormat 时间格式
     * @return 指定日期的前N天
     */
    public static String getBeforeDay(String dateTime, int days, String timeFormat) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(timeFormat);
        Date date = null;
        try {
            date = simpleDateFormat.parse(dateTime);
        } catch (ParseException e) {
            log.error("String转Date日期失败:", e);
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //往前一天
        calendar.add(Calendar.DAY_OF_MONTH, -days);
        return simpleDateFormat.format(calendar.getTime());
    }

    /**
     * 获取当月第一个周三
     *
     * @return 当月第一个周三
     */
    public static String firstWednesday() {
        Calendar cal = Calendar.getInstance();
        //当前年
        int year = cal.get(Calendar.YEAR);
        //当前月
        int month = cal.get(Calendar.MONTH) + 1;
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month - 1); //从0开始
        int day = 1;
        cal.set(Calendar.DAY_OF_MONTH, day);
        //从第一天开始找第一个星期三
        while (cal.get(Calendar.DAY_OF_WEEK) != Calendar.WEDNESDAY) {
            cal.set(Calendar.DAY_OF_MONTH, ++day);
        }
        Date firstWednesday = cal.getTime();
        String dtStr = new SimpleDateFormat("yyyy-MM-dd").format(firstWednesday);
        return dtStr;
    }

    /**
     * 获取指定日期的上N月当天
     *
     * @param n n月
     * @param assignTime 指定日期
     * @param formatPattern 指定日期格式
     * @return 指定日期的上N月当天
     */
    public static String getAssignLastNMonthThisDay(int n,String assignTime,String formatPattern){
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime now1 = LocalDateTime.parse(assignTime,format);

        //获取上个月的当天（这一天）miuns()获取前面月份的方法,参数1为减去的数量，参数2为减去的对象（日，月）
        LocalDateTime minus = now1.minus(n, ChronoUnit.MONTHS);
        String lastMonthThisDay = minus.format(DateTimeFormatter.ofPattern(formatPattern));
        return lastMonthThisDay;
    }

    /**
     * 计算年龄
     *
     * @param birthDate 生日
     * @return 年龄
     */
    public static int age(Date birthDate) {
        // 当前日历
        Calendar nowCalendar = Calendar.getInstance();
        // 生日大于当前日期
        if (nowCalendar.before(birthDate)) {
            throw new IllegalArgumentException("The birth date is before current time, it's unbelievable");
        }
        // 当前年月日
        int yearNow = nowCalendar.get(Calendar.YEAR);
        int monthNow = nowCalendar.get(Calendar.MONTH);
        int dayNow = nowCalendar.get(Calendar.DAY_OF_MONTH);
        // 出生日期年月日
        Calendar birthCalendar = Calendar.getInstance();
        birthCalendar.setTime(birthDate);
        int yearBirth = birthCalendar.get(Calendar.YEAR);
        int monthBirth = birthCalendar.get(Calendar.MONTH);
        int dayBirth = birthCalendar.get(Calendar.DAY_OF_MONTH);
        // 粗计算年龄
        int age = yearNow - yearBirth;
        // 当前月份小于出生月份年龄减一
        if (monthNow < monthBirth) { age--; }
        // 当前月份等于出生月份，日小于生日年龄减一
        else if (monthNow == monthBirth && dayNow < dayBirth) { age--; }
        // 返回年龄值
        return age;
    }
}
